#pragma once
#include <iostream>
#include <string>
#include <cstdio>
#include <memory>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <string>
#include <cstring>
#include "Log.hpp"
#include "InetAddr.hpp"
using namespace ns_log;
static const int gblock = 8;

namespace sock_ns
{
    enum
    {
        SOCKED_ERROR = 1,
        BIND_ERROR,
        LISTEN_ERROR,
        ARROW_COMMAND_ERROE
    };
    using namespace ns_log;
    class Socket;
    using SocketPtr = std::shared_ptr<Socket>;
    // 模板方法模式
    class Socket
    {
    public:
        virtual void CreateSocket() = 0; // 创建一个套接字
        virtual void BindSocket(uint16_t port) = 0;//绑定ip + 端口
        virtual void ListenSocket(int block = gblock) = 0; // 监听
        virtual int AcceptSocket(InetAddr *cliaddr) = 0;//接收client
        virtual bool ConnectSocket(const std::string &serverip, uint16_t serverport) = 0; // 客户端连接
        virtual void Close() = 0;
        virtual ssize_t Recv(std::string *message_out) = 0;//读数据
        virtual ssize_t Send(const std::string &message_out) = 0;//写数据
        virtual void RetryAddress()  = 0;//地址复用
        virtual int SockFd() = 0;
    public:
        void BuildListenSocket(uint16_t port)
        {
            CreateSocket();
            RetryAddress();
            BindSocket(port); 
            ListenSocket();
        }
        bool BuidClientSocket(const std::string &serverip, uint16_t serverport)
        {
            CreateSocket();
            return ConnectSocket(serverip, serverport);
        }
    };
    class Tcp_socket : public Socket
    {
    public:
        Tcp_socket() {}
        Tcp_socket(int sockfd) : _sockfd(sockfd)
        {
        }
        ~Tcp_socket()
        {
            if (_sockfd > 0)
            {
                ::close(_sockfd);
            }
        }
        int SockFd() override
        {
            return _sockfd;
        }
        void RetryAddress() override
        {
            int opt = 0;
            ::setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
        }
        void CreateSocket() override
        {
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                LOG(FATAL, "Create socket error!\n");
                exit(SOCKED_ERROR);
            }
            LOG(INFO, "create sock done!,sockfd = %d\n", _sockfd);
        }
        void BindSocket(uint16_t port) override
        {
            struct sockaddr_in peer;
            memset(&peer, 0, sizeof(peer));
            peer.sin_family = AF_INET;
            peer.sin_addr.s_addr = INADDR_ANY;
            peer.sin_port = htons(port);
            if (::bind(_sockfd, (struct sockaddr *)&peer, sizeof(peer)) < 0)
            {
                LOG(FATAL, "bind error!\n");
                exit(BIND_ERROR);
            }
            LOG(INFO, "bind success!\n");
        }
        void ListenSocket(int block) override
        {
            // 监听连接请求
            if (::listen(_sockfd, block) < 0)
            {
                LOG(FATAL, "listen error!\n");
                exit(LISTEN_ERROR);
            }
            LOG(INFO, "listen succss!\n");
        }
        int AcceptSocket(InetAddr *cliaddr) override
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            // accept连接
            int sockfd = ::accept(_sockfd, (struct sockaddr *)&client, &len);
            if (sockfd < 0)
            {
                // accept失败不需要退出服务器,重新连接即可
                LOG(WARNING, "ACCEPT ERROR!\n");
                //return nullptr;
                return -1;
            }
            *cliaddr = InetAddr(client);
            // LOG(INFO, "Get a new link,mssage = %s\n", cliaddr->GetAddrStr().c_str());
            //return std::make_shared<Tcp_socket>(sockfd);
            return sockfd;
        }
        bool ConnectSocket(const std::string &serverip, uint16_t serverport) override // 客户端
        {
            struct sockaddr_in server; // 发送给谁？？ server！！
            memset(&server, 0, sizeof(server));
            // 填充servrip && port
            server.sin_family = AF_INET;
            // server.sin_addr.s_addr = inet_addr(serverip.c_str());
            ::inet_pton(AF_INET, serverip.c_str(), &server.sin_addr);
            server.sin_port = htons(serverport);
            int n = ::connect(_sockfd, (struct sockaddr *)&server, sizeof(server));
            if (n < 0)
            {
                return false;
            }
            return true;
        }
        void Close() override
        {
            if (_sockfd > 0)
            {
                ::close(_sockfd);
            }
        }
        ssize_t Recv(std::string *packagestreamQueue) override
        {
            char inbuf[4096];
            ssize_t n = ::recv(_sockfd, inbuf, sizeof(inbuf) - 1, 0);
            if (n > 0)
            {
                inbuf[n] = 0;
                *packagestreamQueue += inbuf;
            }
            return n;
        }
        ssize_t Send(const std::string &message_in) override
        {
            ssize_t n = ::send(_sockfd, message_in.c_str(), message_in.size(), 0);
            return n;
        }

    private:
        int _sockfd;
    };
}

